#include "common.h"
#include <pthread.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>

#define RCV_MSG 500

/* 全局变量*/

int fd_file;//有名管道文件描述符
int fd[2];//无名管道的文件描述符数组
int cur_num = 0;//当前歌曲的标号
char buf_msg[RCV_MSG];//歌曲信息存放数组
int lock = 0;
int percent_num = 0;//当前歌曲进度标号
char *song_msg[8] = {"ANS_FILENAME=",//歌曲名 
	"ANS_LENGTH=", //歌曲长度（秒）
	"ANS_META_ARTIST=",// 歌曲作家
	"ANS_META_YEAR=", //歌曲年份
	"ANS_META_GENRE=", //歌曲流派
	"ANS_META_TITLE=", //歌曲标题
	"ANS_META_ALBUM=", //歌曲专辑
	"ANS_META_COMMENT="};//歌曲评论
char *cmd_array[8] = {"get_file_name", 
	"get_time_length", 
	"get_meta_artist", 
	"get_meta_year", 
	"get_meta_genre", 
	"get_meta_title", 
	"get_meta_album", 
	"get_meta_comment"};
sem_t sem;

pthread_mutex_t t_lock = PTHREAD_MUTEX_INITIALIZER;//互斥锁静态定义
pthread_cond_t t_cond = PTHREAD_COND_INITIALIZER;//条件变量静态定义

int auto_debug_lock = 1;//自动播放歌曲全局开关，用于调试
int msg_debug_lock = 1;//信息获取全局开关，用于调试

typedef struct _song_list{//歌曲数目、歌曲名称结构体
	int song_num;
	char song[50][100];
}song_list_t;

song_list_t *list;//全局变量，用于保存歌曲名和歌曲数目


/* 普通子函数 */

/*歌曲列表获取函数*/
void get_song_list(char *pathname);
/*有名管道创建函数*/
void make_fifo(void);
/*命令发送函数*/
void send_cmd(char *cmd);
/*换行符去除函数*/
void abandon_n(char *str);
/*换行符添加函数*/
void add_n(char *str);
/*字符串删减函数*/
char *delete_str(char *str);
/*循环下一首歌曲函数*/
void next_song_loop(void);
/*下一首歌曲函数*/
void next_song(void);
/*循环上一首歌曲函数*/
void prev_song_loop(void);
/*上一首歌曲函数*/
void prev_song(void);


/*子线程 */

void *pthread_auto_play(void *arg)
{
	char buf[RCV_MSG];
	pthread_mutex_lock(&t_lock);
	pthread_cond_wait(&t_cond, &t_lock);
	if(auto_debug_lock == 1)
	{
		while(1)
		{
			char *p_buf = NULL;
			sleep(2);
			send_cmd("get_percent_pos");
			strcpy(buf, buf_msg);
			while((p_buf = strstr(buf, "ANS_PERCENT_POSITION=")) != NULL)
			{
				sleep(1);
				//printf("find : %s\n", p_buf);
				char *p = NULL;
				p = delete_str(p_buf);
				//printf("%s\n", p);
				percent_num = atoi(p);
				printf("num = %d\n", percent_num);
				if(percent_num >= 5)
				{
					//printf("wait auto \n");
					lock = 2;
					sleep(1);
					while(lock == 2)
					{
						next_song_loop();
						lock = 0;
						break;
					}
					sleep(1);//延时，等待temp从设定的判断值变成0
					//printf("jamp auto\n");
				}
				percent_num = 0;
				send_cmd("get_percent_pos");
				strcpy(buf, buf_msg);
				//continue;
			}
			printf("no match\n");
			sleep(10);
			pthread_mutex_unlock(&t_lock);
		}
	}	
	//pthread_mutex_unlock(&t_lock);
	return NULL;
}

void *pthread_get_msg(void *arg)
{
	pthread_mutex_lock(&t_lock);
	pthread_cond_wait(&t_cond, &t_lock);
	sleep(3);
	printf("message print\n");
	//sem_wait(&sem);
	if(msg_debug_lock == 1)
	{
		printf("Get Message\n");
		char buf[RCV_MSG];
		int i = 0;
		while(1)//while(i < 3)
		{
			printf("****<Song Message>****\n");
			sleep(3);
			char *p_buf = NULL;
			
			bzero(buf, RCV_MSG);
			send_cmd(cmd_array[0]);
			strcpy(buf, buf_msg);
			if((p_buf = strstr(buf, song_msg[0])) != NULL)
			{
				printf("find\n");
				sleep(1);
				char *p = NULL;
				p = delete_str(p_buf);
				printf("Song name: %s\n", p);
				p_buf = NULL;
				//break;
			}
			sleep(1);
			bzero(buf, RCV_MSG);
			bzero(buf_msg, RCV_MSG);
			send_cmd(cmd_array[1]);
			strcpy(buf, buf_msg);
			if((p_buf = strstr(buf, song_msg[1])) != NULL)
			{
				printf("find\n");
				sleep(1);
				char *p = NULL;
				p = delete_str(p_buf);
				int time_temp = atoi(p);
				printf("Song length(s): %ds\n", time_temp);
				p_buf = NULL;
				//break;
			}
			i++;
		}
		printf("ok\n");
		msg_debug_lock = 0;
		//sem_post(&sem);
	}
	pthread_mutex_unlock(&t_lock);
	
	return NULL;
}

void *pthread_read_pipe(void *arg)
{
	close(fd[1]);
	ssize_t count;
	char buf[RCV_MSG];
	while(1)
	{
		memset(buf, 0, RCV_MSG);
		count = read(fd[0], buf, sizeof(buf));
		if(count < 0)
			err_sys("read fail\n");
		if(count == 0)
			continue;

		buf[count] = '\0';

		strcpy(buf_msg, buf);
		printf("%s\n", buf_msg);//打印全部歌曲信息
	}

	return NULL;
}

void *pthread_send_cmd(void *arg)
{
	sleep(2);
	//printf("\nPlease input command : \n");
	while(1)
	{
		pthread_mutex_lock(&t_lock);
		printf("\nPlease input command : \n");
		char *cmd = NULL;
		cmd = (char *)malloc(sizeof(char) * 1024);

		fgets(cmd, 1024, stdin);
		abandon_n(cmd);
		if(strcmp(cmd, "next") == 0)
		{
			//next_song();
			next_song_loop();
		}
		else if(strcmp(cmd, "list") == 0)
		{
			printf("***<Songs List>***\n");
			get_song_list("./");			
		}
		else if(strcmp(cmd, "prev") == 0)
		{
			//prev_song();
			prev_song_loop();
		}
		else if((strstr(cmd, ">") != NULL) || (strstr(cmd, "<") != NULL))
		{
			printf("Rate Adjust.\n");
			char *p = NULL;
			while(*cmd != '\0'){
				p = cmd;
				if((*p == '<') || (*p == '>')){
					p = p + 1;
					break;
				}
				cmd++;
			}	
			
			ssize_t count = 0;
			char cmd_buf[100];
			sprintf(cmd_buf, "seek %s\n", p);
			count = write(fd_file, cmd_buf, strlen(cmd_buf));
			if(count != strlen(cmd_buf))
				err_sys("write error\n");
		}
		else if((strstr(cmd, "~") != NULL))
		{
			printf("Volume Adjust.\n");
			//sleep(1);
			char *p = NULL;
			while(*cmd != '\0'){
				p = cmd;
				if(*p == '~'){
					p = p + 1;
					break;
				}
				cmd++;
			}	
			int v_temp = atoi(p);
			ssize_t count = 0;
			char cmd_buf[100];
			sprintf(cmd_buf, "volume %d 1\n", v_temp);
			count = write(fd_file, cmd_buf, strlen(cmd_buf));
			if(count != strlen(cmd_buf))
				err_sys("write error\n");
		}
		else if(strcmp(cmd, "message") == 0)
		{
			printf("to get message\n");
			msg_debug_lock = 1;
			//break;
		}
		else if(strcmp(cmd, "autoplay") == 0)
		{
			printf("to auto play\n");
			sem_wait(&sem);
			auto_debug_lock = 1;
			sem_post(&sem);
			//break;
		}
		else
		{
			//add_n(cmd);
			send_cmd(cmd);
		}
		//pthread_mutex_unlock(&t_lock);
		//pthread_cond_signal(&t_cond);
		sleep(2);
	}	
	sleep(1);
	pthread_mutex_unlock(&t_lock);
	pthread_cond_signal(&t_cond);
	return NULL;
}


int main()
{
	if(pipe(fd) < 0)//创建无名管道
		err_sys("pipe error\n");
	make_fifo();//创建有名管道
	get_song_list("./");//获取当前目录下所有mp3格式的歌曲文件

	pid_t pid;
	pid = fork();
	if(pid < 0)
		err_sys("fork error\n");
	else if(pid == 0)
	{
		close(fd[0]);
		dup2(fd[1], 1);
		execlp("mplayer", "mplayer", "-slave", "-quiet", "-idle", "-input", "file=./cmdfifo", list->song[0], NULL);	
	}
	else
	{
		pthread_t tid_read;
		pthread_t tid_send_cmd;
		pthread_t tid_get_msg;
		pthread_t tid_auto_play;

		sleep(1);
		
		int ret = sem_init(&sem, 0, 1);
		if(ret < 0)
			err_sys("sem_init error\n");
		
		fd_file = open("./cmdfifo", O_RDWR);
		if(fd_file < 0)
			err_sys("open cmdfifo error\n");

		pthread_create(&tid_read, NULL, pthread_read_pipe, NULL);
		pthread_create(&tid_send_cmd, NULL, pthread_send_cmd, NULL);
		pthread_create(&tid_get_msg, NULL, pthread_get_msg, NULL);
		pthread_create(&tid_auto_play, NULL, pthread_auto_play, NULL);
		
		pthread_join(tid_read, NULL);
		pthread_join(tid_send_cmd, NULL);
		pthread_join(tid_get_msg, NULL);
		pthread_join(tid_auto_play, NULL);
	}
	return 0;
}


void prev_song(void){
	ssize_t count = 0;
	char cmd_buf[100];
	cur_num--;
	if(cur_num < 0){
		printf("\nIt is the first song!\n\n");
		sleep(1);
		cur_num = 0;
	}
	sprintf(cmd_buf, "loadfile %s\n", list->song[cur_num]);
	count = write(fd_file, cmd_buf, strlen(cmd_buf));
	if(count != strlen(cmd_buf))
		err_sys("write error\n");
}

void prev_song_loop(void){
	ssize_t count = 0;
	char cmd_buf[100];
	cur_num--;
	if(cur_num < 0){
		printf("\nIt is the first song!\n\n");
		sleep(1);
		cur_num = 0 + list->song_num - 1;
	}
	sprintf(cmd_buf, "loadfile %s\n", list->song[cur_num]);
	count = write(fd_file, cmd_buf, strlen(cmd_buf));
	if(count != strlen(cmd_buf))
		err_sys("write error\n");
}

void next_song(void){
	ssize_t count = 0;
	char cmd_buf[100];
	cur_num++;
	if(cur_num >= list->song_num){
		printf("\nSorry, there are only %d songs!\n\n", list->song_num);
		sleep(1);
		cur_num = list->song_num - 1;
	}
	sprintf(cmd_buf, "loadfile %s\n", list->song[cur_num]);
	count = write(fd_file, cmd_buf, strlen(cmd_buf));
	if(count != strlen(cmd_buf))
		err_sys("write error\n");
}

void next_song_loop(void){
	ssize_t count = 0;
	char cmd_buf[100];
	cur_num++;
	if(cur_num >= list->song_num){
		printf("\nSorry, there are only %d songs!\n\n", list->song_num);
		sleep(1);
		cur_num = cur_num - list->song_num;
	}
	sprintf(cmd_buf, "loadfile %s\n", list->song[cur_num]);
	count = write(fd_file, cmd_buf, strlen(cmd_buf));
	if(count != strlen(cmd_buf))
		err_sys("write error\n");
}

char *delete_str(char *str){
	char *p = NULL;
	p = (char *)malloc(sizeof(char) * strlen(str));
	if(p == NULL)
		err_sys("malloc error\n");
	while(*str != '\0'){
		p = str;
		if(*p == '='){
			p = p + 1;
			break;
		}
		str++;
	}	
	return p;
}

void abandon_n(char *str){
	char *find = NULL;
	find = (char *)malloc(sizeof(char));
	if(find == NULL)
		err_sys("malloc error\n");
	find = strchr(str, '\n');
	if(find == NULL){
		err_sys("find fail\n");
	}
	else{
		*find = '\0';
	}
}

void add_n(char *str){
	char *find = NULL;
	find = (char *)malloc(sizeof(char));
	if(find == NULL)
		err_sys("malloc error\n");
	find = strchr(str, '\0');
	if(find == NULL){
		err_sys("find fail\n");
	}
	else{
		*find = '\n';
	}
}

void send_cmd(char *cmd){
	//printf("send command\n");
	ssize_t count = 0;
	char cmd_buf[100];
	sprintf(cmd_buf, "%s\n", cmd);
	count = write(fd_file, cmd_buf, strlen(cmd_buf));
	if(count != strlen(cmd_buf))
		err_sys("write error\n");
}

void get_song_list(char *pathname){
	list = (song_list_t *)malloc(sizeof(song_list_t));
	if(list == NULL)
		err_sys("malloc error\n");
	list->song_num = 0;

	DIR *song_dir = opendir(pathname);
	if(song_dir == NULL)
		err_sys("opendir error\n");

	struct dirent *read_dir = readdir(song_dir);
	while(read_dir != NULL){
		if(strstr(read_dir->d_name, ".mp3") != NULL){
			strcpy(list->song[list->song_num], read_dir->d_name);
			printf("%d. %s\n", (list->song_num + 1), read_dir->d_name);
			list->song_num++;
		}
		read_dir = readdir(song_dir);
	}
	printf("\nThere are %d songs\n\n", list->song_num);
	closedir(song_dir);
}

void make_fifo(void){
	if(access("./cmdfifo", F_OK) == 0){
		printf("fifo exist\n");
		unlink("./cmdfifo");
		mkfifo("./cmdfifo", 0666);
	}
	else{
		mkfifo("./cmdfifo", 0666);
	}
}
